package com.lsec.springbootinit.service;


import cn.hutool.jwt.JWTUtil;
import com.lsec.springbootinit.config.TokenProperties;
import com.lsec.springbootinit.constant.CacheConstants;
import com.lsec.springbootinit.constant.Constants;
import com.lsec.springbootinit.model.common.LoginUser;
import com.lsec.springbootinit.utils.RedisCache;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * 令牌服务
 *
 * @author Cherry
 * @date 2023/06/27
 */
@Component
@RequiredArgsConstructor
public class TokenService {

    private final TokenProperties tokenProperties;
    private final RedisCache redisCache;
    private final RedisTemplate<String, Object> redisTemplate;

    protected static final long MILLIS_SECOND = 1000;

    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;


    /**
     * 创建令牌
     *
     * @param userId 用户id
     * @return {@link String}
     */
    public String createToken(Long userId) {
        return JWTUtil.createToken(
                Collections.singletonMap(Constants.USER_ID, userId),
                tokenProperties.getSecretKey().getBytes()
        );
    }


    /**
     * 验证令牌有效期，相差不足20分钟，自动刷新缓存
     *
     * @param loginUser 登录用户
     */
    public void verifyToken(LoginUser loginUser) {
        Long loginTime = loginUser.getLoginTime();
        long expireTime = loginUser.getExpireTime();
        long currentTime = System.currentTimeMillis();
        // 判断是否需要刷新 (令牌过期时间 - 当前时间 < 自定义规定的可刷新时间)  && (登录时间 + 规定最长刷新令牌时间) >= 当前时间
        if (expireTime - currentTime <= tokenProperties.getRefreshValidityPeriod() * MILLIS_SECOND && (loginTime + tokenProperties.getLongExpirationTime() * MILLIS_SECOND) >= currentTime) {
            refreshToken(loginUser);
        }
    }

    /**
     * 刷新令牌有效期
     *
     * @param loginUser 登录信息
     */
    public void refreshToken(LoginUser loginUser) {

        Long expirationTime = tokenProperties.getExpirationTime();
        long currentTime = System.currentTimeMillis();

        loginUser.setExpireTime(currentTime + expirationTime * MILLIS_SECOND);
        loginUser.setRefreshTime(currentTime);
        // 首次登录 存储首次登陆时间且不变更值 为了实现长令牌的刷新
        if (loginUser.getLoginTime() == null) {
            loginUser.setLoginTime(currentTime);
        }
        // 将令牌存储到 redis中 过期时间秒
        redisCache.setCacheObject(CacheConstants.AUTH_USER_KEY + loginUser.getSysUser().getId(), loginUser, expirationTime, TimeUnit.SECONDS);
    }
}
